class Request {
  config = {
    baseUrl: '', // 请求的根域名
    // 默认的请求头
    header: {
      'content-type': 'application/json'
    },
    method: 'POST',
    // 设置为json，返回后uni.request会对数据进行一次JSON.parse
    dataType: 'json',
    // 此参数无需处理，因为5+和支付宝小程序不支持，默认为text即可
    responseType: 'text',
    showLoading: true, // 是否显示请求中的loading
    loadingText: '请求中...',
    loadingTime: 800, // 在此时间内，请求还没回来的话，就显示加载中动画，单位ms
    timer: null, // 定时器
    originalData: true, // 是否在拦截器中返回服务端的原始数据，见文档说明
    loadingMask: true // 展示loading的时候，是否给一个透明的蒙层，防止触摸穿透
  }

  // 判断是否http|https开头的URL
  static isHttp(url) {
    return /(http|https):\/\/([\w.]+\/?)\S*/.test(url)
  }

  // 拦截器
  interceptor = {
    // 请求前的拦截
    request: null,
    // 请求后的拦截
    response: null
  }

  // 设置全局默认配置
  setConfig(customConfig) {
    this.config = Object.assign(this.config, customConfig)
  }

  // 主要请求部分
  async request(options = {}) {
    // 检查请求拦截
    if (
      this.interceptor.request &&
      typeof this.interceptor.request === 'function'
    ) {
      const interceptorReuest = this.interceptor.request(options)
      if (interceptorReuest === false) {
        return false
      }
      this.options = interceptorReuest
    }

    options.dataType = options.dataType || this.config.dataType
    options.responseType = options.responseType || this.config.responseType
    options.url = options.url || ''
    let params = {}
    const trim = v =>
      typeof v === 'string' ? v.replace(/(^\s+)|(\s+$)/g, '') : v
    if (options.params) {
      Object.keys(options.params).forEach(v => {
        params[trim(v)] = trim(options.params[v])
      })
      options.params = params
    }
    options.header = Object.assign(this.config.header, options.header)
    options.method = options.method || this.config.method

    return new Promise((resolve, reject) => {
      options.complete = response => {
        // 请求返回后，隐藏loading(如果请求返回快的话，可能会没有loading)
        uni.hideLoading()
        // 清除定时器，如果请求回来了，就无需loading
        clearTimeout(this.config.timer)
        this.config.timer = null
        // 判断用户对拦截返回数据的要求，如果originalData为true，返回所有的数据(response)到拦截器，否则只返回response.data
        if (this.config.originalData) {
          // 判断是否存在拦截器
          if (
            this.interceptor.response &&
            typeof this.interceptor.response === 'function'
          ) {
            const resInterceptors = this.interceptor.response(response)
            // 如果拦截器不返回false，就将拦截器返回的内容给this.$u.post的then回调
            if (resInterceptors !== false) {
              resolve(resInterceptors)
            } else {
              // 如果拦截器返回false，意味着拦截器定义者认为返回有问题，直接接入catch回调
              reject(response)
            }
          } else {
            // 如果要求返回原始数据，就算没有拦截器，也返回最原始的数据
            resolve(response)
          }
        } else {
          if (response.statusCode === 200) {
            if (
              this.interceptor.response &&
              typeof this.interceptor.response === 'function'
            ) {
              const resInterceptors = this.interceptor.response(response.data)
              if (resInterceptors !== false) {
                resolve(resInterceptors)
              } else {
                reject(response)
              }
            } else {
              // 如果不是返回原始数据(originalData=false)，且没有拦截器的情况下，返回纯数据给then回调
              resolve(response.data)
            }
          } else {
            // 不返回原始数据的情况下，服务器状态码不为200，modal弹框提示
            if (response.errMsg) {
              uni.showToast({
                title: response.errMsg,
                icon: 'none'
              })
            }
            reject(response)
          }
        }
      }

      // 判断用户传递的URL是否/开头,如果不是,加上/
      options.url = Request.isHttp(options.url)
        ? options.url
        : this.config.baseUrl +
          (options.url.indexOf('/') === 0 ? options.url : '/' + options.url)

      // 是否显示loading
      // 加一个是否已有timer定时器的判断，否则有两个同时请求的时候，后者会清除前者的定时器id
      // 而没有清除前者的定时器，导致前者超时，一直显示loading
      if (this.config.showLoading && !this.config.timer) {
        this.config.timer = setTimeout(() => {
          uni.showLoading({
            title:
              (options.config && options.config.loadingText) ||
              this.config.loadingText,
            mask: this.config.loadingMask
          })
        }, this.config.loadingTime)
      }
      uni.request(options)
    })
  }

  constructor() {
    // get请求
    this.get = (url, data = {}, header = {}) => {
      return this.request({
        method: 'GET',
        url,
        header,
        data
      })
    }

    // post请求
    this.post = (url, data = {}, config = {}, header = {}) => {
      return this.request({
        url,
        method: 'POST',
        header,
        data,
        config
      })
    }

    // put请求，不支持支付宝小程序(HX2.6.15)
    this.put = (url, data = {}, header = {}) => {
      return this.request({
        url,
        method: 'PUT',
        header,
        data
      })
    }

    // delete请求，不支持支付宝和头条小程序(HX2.6.15)
    this.delete = (url, data = {}, header = {}) => {
      return this.request({
        url,
        method: 'DELETE',
        header,
        data
      })
    }
  }
}
export default new Request()
